package jef.tools.resource;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;

/**
 * Interface for a resource descriptor that abstracts from the actual type of
 * underlying resource, such as a file or class path resource.
 * 
 * <p>
 * An InputStream can be opened for every resource if it exists in physical
 * form, but a URL or File handle can just be returned for certain resources.
 * The actual behavior is implementation-specific.
 * 
 * @author Juergen Hoeller
 * @since 28.12.2003
 * @see #getInputStream()
 * @see #getURL()
 * @see #getURI()
 * @see #getFile()
 * @see WritableResource
 * @see ContextResource
 * @see FileSystemResource
 * @see ClassPathResource
 * @see UrlResource
 * @see ByteArrayResource
 * @see InputStreamResource
 */
public interface IResource {

	/**
	 * Return an {@link InputStream}.
	 * <p>It is expected that each call creates a <i>fresh</i> stream.
	 * <p>This requirement is particularly important when you consider an API such
	 * as JavaMail, which needs to be able to read the stream multiple times when
	 * creating mail attachments. For such a use case, it is <i>required</i>
	 * that each <code>getInputStream()</code> call returns a fresh stream.
	 * @return the input stream for the underlying resource (must not be {@code null})
	 * @throws IOException if the stream could not be opened
	 */
	InputStream getInputStream() throws IOException;

	/**
	 * Return whether this resource actually exists in physical form.
	 * <p>
	 * This method performs a definitive existence check, whereas the existence
	 * of a <code>Resource</code> handle only guarantees a valid descriptor
	 * handle.
	 */
	boolean exists();

	/**
	 * Return whether the contents of this resource can be read, e.g. via
	 * {@link #getInputStream()} or {@link #getFile()}.
	 * <p>
	 * Will be <code>true</code> for typical resource descriptors; note that
	 * actual content reading may still fail when attempted. However, a value of
	 * <code>false</code> is a definitive indication that the resource content
	 * cannot be read.
	 * 
	 * @see #getInputStream()
	 */
	boolean isReadable();

	/**
	 * Return whether this resource represents a handle with an open stream. If
	 * true, the InputStream cannot be read multiple times, and must be read and
	 * closed to avoid resource leaks.
	 * <p>
	 * Will be <code>false</code> for typical resource descriptors.
	 */
	boolean isOpen();

	/**
	 * Return a URL handle for this resource.
	 * 
	 * @throws IOException
	 *             if the resource cannot be resolved as URL, i.e. if the
	 *             resource is not available as descriptor
	 */
	URL getURL();

	/**
	 * Return a URI handle for this resource.
	 * 
	 * @throws IOException
	 *             if the resource cannot be resolved as URI, i.e. if the
	 *             resource is not available as descriptor
	 */
	URI getURI() throws IOException;

	/**
	 * Return a File handle for this resource.
	 * 
	 * @throws IOException
	 *             if the resource cannot be resolved as absolute file path,
	 *             i.e. if the resource is not available in a file system
	 */
	File getFile() throws IOException;

	/**
	 * Determine the content length for this resource.
	 * 
	 * @throws IOException
	 *             if the resource cannot be resolved (in the file system or as
	 *             some other known physical resource type)
	 */
	long contentLength() throws IOException;

	/**
	 * Determine the last-modified timestamp for this resource.
	 * 
	 * @throws IOException
	 *             if the resource cannot be resolved (in the file system or as
	 *             some other known physical resource type)
	 */
	long lastModified() throws IOException;

	/**
	 * Create a resource relative to this resource.
	 * 
	 * @param relativePath
	 *            the relative path (relative to this resource)
	 * @return the resource handle for the relative resource
	 * @throws IOException
	 *             if the relative resource cannot be determined
	 */
	IResource createRelative(String relativePath) throws IOException;

	/**
	 * Determine a filename for this resource, i.e. typically the last part of
	 * the path: for example, "myfile.txt".
	 * <p>
	 * Returns <code>null</code> if this type of resource does not have a
	 * filename.
	 */
	String getFilename();

	/**
	 * Return a description for this resource, to be used for error output when
	 * working with the resource.
	 * <p>
	 * Implementations are also encouraged to return this value from their
	 * <code>toString</code> method.
	 * 
	 * @see java.lang.Object#toString()
	 */
	String getDescription();

	boolean isFile();

}
